package com.test.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.test.utils.AESUtils;
import com.test.utils.DateUtil;
import com.test.utils.JsonUtil;

import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JSON Web Token（JWT）是目前最流行的跨域身份验证解决方案
 * <dependency>
 *     <groupId>com.auth0</groupId>
 *     <artifactId>java-jwt</artifactId>
 *     <version>3.10.0</version>
 * </dependency>
 *
 * 1.用户向服务器发送用户名和密码。
 * 2.验证服务器后，相关数据（如用户角色，登录时间等）将保存在当前会话中。
 * 3.服务器向用户返回session_id，session信息都会写入到用户的Cookie。
 * 4.用户的每个后续请求都将通过在Cookie中取出session_id传给服务器。
 * 5.服务器收到session_id并对比之前保存的数据，确认用户的身份。
 */
public class JwtDemo {
    public static void main(String[] main) {
        jwt1();
        jwt2();
    }

    public static void jwt1() {
        try {
            //创建加密算法
            Algorithm algorithm = Algorithm.HMAC256("secret");
            String token = JWT.create()
                    //签发者
                    .withIssuer("auth0")
                    //自定义KV
                    .withClaim("admin", "jack")
                    .withClaim("role", "admin")
                    //过期时间,必须大于签发时间
//                    .withExpiresAt(DateUtil.da(DateUtil.nowDate(), ChronoUnit.MINUTES, 30))
                    //生效时间,定义在什么时间之前,该Token都是不可用的
                    .withNotBefore(new Date())
                    //签发时间,一般为当前时间
                    .withIssuedAt(new Date())
                    .sign(algorithm);
            System.out.println(token);
        } catch (JWTCreationException exception) {
            //Invalid Signing configuration / Couldn't convert Claims.
        }
    }

    public static void jwt2() {
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCIsImFkbWluIjoiamFjayIsImlhdCI6MTU4MzkxMjIxOH0.8aTS51RiyNs9lEjLDvSr7SHb_ON2x6E4zeJGWAo_IsI";
        try {
            //创建加密算法
            Algorithm algorithm = Algorithm.HMAC256("secret");
            JWTVerifier verifier = JWT.require(algorithm)
                    //可以强制判断token当中是否包含此字段
                    .withIssuer("auth0")
                    .withClaim("admin", "jack")
                    //单位秒: 可以接受过期的时间长度,
                    //比如过期时间为15:30:00,可以往后延45秒，那么过期时间为15:30:45
                    .acceptExpiresAt(45)
                    //单位秒：可以接受提前使用的时间长度，
                    //比如NotBefore定以为15:30:00，那么在到时间之前正常token都不可用
                    //设置为60，代表提前一分钟可以用  那么token在15:29:00就可以用了
                    .acceptNotBefore(60)
                    .build();
            DecodedJWT jwt = verifier.verify(token);

            System.out.println(jwt.getClaim("admin").asString());
            System.out.println(jwt.getExpiresAt());
            System.out.println(jwt.getIssuedAt());
        } catch (JWTVerificationException exception) {
            //Invalid signature/claims
            exception.printStackTrace();
        }
    }

    public static void jwt3() {
        try {

            Map<String, Object> map = new HashMap<>();
            map.put("id", 9223372036854775807L);
            map.put("role", "administrator");
            map.put("ip", "192.168.245.245");
            String value = AESUtils.encode(JsonUtil.toJson(map), "LJkbctuTzQsQv6WZ");
            //创建加密算法
            Algorithm algorithm = Algorithm.HMAC256("LJkbctuTzQsQv6WZ");
            
            String token = JWT.create()
                    //签发者
                    .withIssuer("fjfruits.cn")
                    //自定义KV
                    .withClaim("tk", value)
                    //过期时间,必须大于签发时间
//                    .withExpiresAt(DateUtil.timePlus(DateUtil.nowDate(), ChronoUnit.MINUTES, 30))
                    //生效时间,定义在什么时间之前,该Token都是不可用的
                    .withNotBefore(new Date())
                    //签发时间,一般为当前时间
                    .withIssuedAt(new Date())
                    .sign(algorithm);
            System.out.println(token.getBytes().length + "=>" + token);


            //创建加密算法
            JWTVerifier verifier = JWT.require(algorithm)
                    //可以强制判断token当中是否包含此字段
                    .withIssuer("fjfruits.cn")
                    //单位秒: 可以接受过期的时间长度,
                    //比如过期时间为15:30:00,可以往后延45秒，那么过期时间为15:30:45
                    .acceptExpiresAt(45)
                    //单位秒：可以接受提前使用的时间长度，
                    //比如NotBefore定以为15:30:00，那么在到时间之前正常token都不可用
                    //设置为60，代表提前一分钟可以用  那么token在15:29:00就可以用了
                    .acceptNotBefore(60)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            String jsonStr = AESUtils.decode(jwt.getClaim("tk").asString(), "LJkbctuTzQsQv6WZ");
            System.out.println(JsonUtil.jsonToMap(jsonStr).get("ip"));
            System.out.println(jwt.getExpiresAt());
            System.out.println(jwt.getIssuedAt());

        } catch (JWTCreationException exception) {
            //Invalid Signing configuration / Couldn't convert Claims.
        }
    }
}
